/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.funda.xmppserver.writer;

import com.funda.xmppserver.XMPPClient;
import com.funda.xmppserver.XMPPInfo;
import com.funda.xmppserver.mysql.DBManager;
import com.funda.xmppserver.presence.PresenceManager;
import com.funda.xmppserver.roster.Roster;
import com.funda.xmppserver.usermanager.Users;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

/**
 *
 * @author kurinchi
 */
public class XMPPPacketWriter extends Thread {

    DataOutputStream writer;
    XMLOutputFactory xof;
    XMLStreamWriter streamwriter;
    XMPPClient client;

    public XMPPClient getClient() {
        return client;
    }

    public void setClient(XMPPClient client) {
        this.client = client;
    }

    public XMPPPacketWriter(DataOutputStream writer, XMPPClient client) {

        this.writer = writer;
        this.client = client;
    }

    public void sendStreamResponse() {
        try {
            writer.write(("<stream:stream from='" + XMPPInfo.getHOST() + "' id='" + UUID.randomUUID().toString() + "' xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' xml:lang='en' version='1.0'>").getBytes());

            if (client.isAuthenticated()) {
                writer.write("<stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></stream:features>".getBytes());
            } else {
                writer.write("<stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>PLAIN</mechanism></mechanisms><register xmlns='http://jabber.org/features/iq-register' /></stream:features>".getBytes());
            }
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendSuccess() {
        try {
            writer.write("<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>".getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendFailure() {
        try {
            writer.write("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>".getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void closeStream() {
        try {
            writer.write("</stream:stream>".getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendbindResponse(String id, String clientjid) {
        try {
            writer.write(("<iq from='" + XMPPInfo.getHOST() + "' id='" + id + "' type='result'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><jid>" + clientjid + "</jid></bind></iq>").getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendsessionResponse(String id) {
        try {
            writer.write(("<iq from='" + XMPPInfo.getHOST() + "' type='result' id='" + id + "'/>").getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void senddiscoResponse(String id, String jid) {
        try {
            writer.write(("<iq id='" + id + "' type='error' to='" + jid + "' from='" + XMPPInfo.getHOST() + "'><query xmlns='http://jabber.org/protocol/disco#items'/><error code='501' type='cancel'><feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error></iq>").getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendagentsResponse(String id, String jid) {
        try {
            writer.write(("<iq id='" + id + "' type='error' to='" + jid + "' from='" + XMPPInfo.getHOST() + "'><query xmlns='jabber:iq:agents'/><error code='501' type='cancel'><feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error></iq>").getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendrosterResponse(String id, String jid, String rosteritems) {
        try {
            writer.write(("<iq xmlns='jabber:client' to='" + jid + "' type='result' id='" + id + "'><query xmlns='jabber:iq:roster'>" + rosteritems + "</query></iq>").getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendinitregisterResponse(String id)
    {
        try {
            writer.write(("<iq xmlns='jabber:client' from='"+XMPPInfo.getHOST()+"' type='result' id='"+id+"'><query xmlns='jabber:iq:register'><username /><password /><email /><name /><x xmlns='jabber:x:data' type='form'><title>XMPP Client Registration</title><instructions>Please provide the following information</instructions><field type='hidden' var='FORM_TYPE'><value>jabber:iq:register</value></field><field label='Username' var='username' type='text-single'><required /></field><field label='Full name' var='name' type='text-single' /><field label='Email' var='email' type='text-single' /><field label='Password' var='password' type='text-private'><required /></field></x></query></iq>").getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendregisterResponse(String id)
    {
        try {
            writer.write(("<iq xmlns='jabber:client' from='"+XMPPInfo.getHOST()+"' to='"+XMPPInfo.getHOST()+"' type='result' id='"+id+"' />").getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendregisterconflictResponse(String id,String username,String password)
    {
        try {
            writer.write(("<iq xmlns='jabber:client' from='"+XMPPInfo.getHOST()+"' to='"+XMPPInfo.getHOST()+"' type='error' id='"+id+"'><query xmlns='jabber:iq:register'><username>"+username+"</username><password>"+password+"</password></query><error code='409' type='cancel'><conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' /></error></iq>").getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void updateAllRoster(PresenceManager presencemanager, ArrayList<Object> showlist, String type) {
        Roster roster = client.getRoster();
        Map rosteritems = roster.getRosteritems();

        Map userjids = Users.getUserjidlist();

        Map users = Users.getUserlist();

        for (Object key : rosteritems.keySet()) {
            System.out.println(key.toString());
            String usrkey = key.toString().substring(0, key.toString().indexOf('@'));
            if (userjids.containsKey(usrkey)) {
                List list = (List) userjids.get(usrkey);
                Iterator itr = list.iterator();
                while (itr.hasNext()) {
                    try {
                        String rosterjid = (String) itr.next();
                        XMPPClient cli = (XMPPClient) users.get(rosterjid);
                        System.out.println(rosterjid + " : " + cli.getUsername());
                        DataOutputStream rosterwriter = cli.getWriter();

                        //sends client presence to roster items
                        rosterwriter.write(("<presence xmlns='jabber:client' from='" + client.getJid() + "' to='" + key.toString() + "' " + (type.equalsIgnoreCase("unavailable") ? "type='unavailable'" : "") + "><priority>" + presencemanager.getpriority() + "</priority><status >" + presencemanager.getStatus() + "</status>" + (presencemanager.getShow() != 0 ? "<show>" + showlist.get(presencemanager.getShow()) + "</show>" : "") + "<x xmlns='vcard-temp:x:update'><photo></photo></x></presence>").getBytes());

                        //sends roster items presence to client
                        writer.write(("<presence xmlns='jabber:client' from='" + rosterjid + "' to='" + client.getJid() + "'><priority>" + cli.getPresencemanager().getpriority() + "</priority><status>" + cli.getPresencemanager().getStatus() + "</status>" + (cli.getPresencemanager().getShow() != 0 ? "<show>" + showlist.get(cli.getPresencemanager().getShow()) + "</show>" : "") + "<x xmlns='vcard-temp:x:update'><photo></photo></x></presence>").getBytes());


                    } catch (IOException ex) {
                        Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
                    }


                }
            }

        }

    }

    public void sendMessage(String to, String msg, String timestamp) {
        Map userjids = Users.getUserjidlist();
        Map users = Users.getUserlist();

        System.out.println(to + ":" + to.substring(0, to.indexOf('@')));
        if (!users.containsKey(to) && !userjids.containsKey(to.substring(0, to.indexOf('@')))) {
            System.out.println("User Offline : " + to);
            DBManager.updateChatHistory(client.getJid().toString(), to, msg, timestamp, true);
            return;
        }

        if (to.contains("/")) {
            try {
                XMPPClient cli = (XMPPClient) users.get(to);
                System.out.println(to + " : " + cli.getUsername());
                DataOutputStream rosterwriter = cli.getWriter();
                rosterwriter.write(("<message xmlns='jabber:client' from='" + client.getJid() + "' to='" + to + "' type='chat'><body>" + msg + "</body></message>").getBytes());
                DBManager.updateChatHistory(client.getJid().toString(), to, msg, timestamp, false);
                return;
            } catch (IOException ex) {
                Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
            }
        }


        String usrkey = to.substring(0, to.indexOf('@'));
        if (userjids.containsKey(usrkey)) {
            List list = (List) userjids.get(usrkey);
            Iterator itr = list.iterator();
            while (itr.hasNext()) {
                try {
                    String rosterjid = (String) itr.next();
                    XMPPClient cli = (XMPPClient) users.get(rosterjid);
                    System.out.println(rosterjid + " : " + cli.getUsername());
                    DataOutputStream rosterwriter = cli.getWriter();
                    rosterwriter.write(("<message xmlns='jabber:client' from='" + client.getJid() + "' to='" + rosterjid + "' type='chat'><body>" + msg + "</body></message>").getBytes());

                    DBManager.updateChatHistory(client.getJid().toString(), rosterjid, msg, timestamp, false);


                } catch (IOException ex) {
                    Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
                }


            }
        }
    }

    public void sendXDelayMsg(String from, String msg, String timestamp) {
        try {
            writer.write(("<message xmlns='jabber:client' from='" + (from+"@"+XMPPInfo.getHOST()) + "' to='" + client.getJid() + "' type='chat'><body>" + msg + "</body><x xmlns='jabber:x:delay' stamp='" + timestamp + "' /></message>").getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public void sendSubscriptionrequsetResponse(String jid, String id) {
        try {
            writer.write(("<iq xmlns='jabber:client' to='" + client.getJid() + "' type='set' id='" + UUID.randomUUID().toString() + "'><query xmlns='jabber:iq:roster'><item jid='" + jid + "' subscription='none' /></query></iq>").getBytes());
            writer.write(("<iq xmlns='jabber:client' to='" + client.getJid() + "' type='result' id='" + id + "' />").getBytes());
            writer.write(("<iq xmlns='jabber:client' to='" + client.getJid() + "' type='set' id='" + UUID.randomUUID().toString() + "'><query xmlns='jabber:iq:roster'><item ask='subscribe' jid='" + jid + "' subscription='none' /></query></iq>").getBytes());
        } catch (IOException ex) {
            Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void sendSubscriptionrequestPresence(String to) {

        Map userjids = Users.getUserjidlist();
        Map users = Users.getUserlist();

        System.out.println(to + ":" + to.substring(0, to.indexOf('@')));
        if (!users.containsKey(to) && !userjids.containsKey(to.substring(0, to.indexOf('@')))) {
            System.out.println("User Offline : " + to);
            //DBManager.updateChatHistory(client.getJid().toString(), to, msg, timestamp, true);
            return;
        }

        String usrkey = to.substring(0, to.indexOf('@'));
        if (userjids.containsKey(usrkey)) {
            List list = (List) userjids.get(usrkey);
            Iterator itr = list.iterator();
            while (itr.hasNext()) {
                try {
                    String rosterjid = (String) itr.next();
                    XMPPClient cli = (XMPPClient) users.get(rosterjid);
                    System.out.println(rosterjid + " : " + cli.getUsername());
                    DataOutputStream rosterwriter = cli.getWriter();
                    rosterwriter.write(("<presence xmlns='jabber:client' from='" + (client.getUsername() + "@" + XMPPInfo.getHOST()) + "' to='" + to + "' type='subscribe' />").getBytes());

                    //DBManager.updateChatHistory(client.getJid().toString(), rosterjid, msg, timestamp, false);


                } catch (IOException ex) {
                    Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
                }


            }
        }

    }

    public void sendSubscriptionApprovedResponse(String to) {
        Map userjids = Users.getUserjidlist();
        Map users = Users.getUserlist();

        System.out.println(to + ":" + to.substring(0, to.indexOf('@')));
        if (!users.containsKey(to) && !userjids.containsKey(to.substring(0, to.indexOf('@')))) {
            System.out.println("User Offline : " + to);
            //DBManager.updateChatHistory(client.getJid().toString(), to, msg, timestamp, true);
            return;
        }

        String usrkey = to.substring(0, to.indexOf('@'));
        if (userjids.containsKey(usrkey)) {
            List list = (List) userjids.get(usrkey);
            Iterator itr = list.iterator();
            while (itr.hasNext()) {
                try {
                    String rosterjid = (String) itr.next();
                    XMPPClient cli = (XMPPClient) users.get(rosterjid);
                    System.out.println(rosterjid + " : " + cli.getUsername());
                    DataOutputStream rosterwriter = cli.getWriter();


                    

                    rosterwriter.write(("<presence xmlns='jabber:client' from='" + client.getBareJID() + "' to='" + to + "' type='subscribed' />").getBytes());
                    rosterwriter.write(("<iq xmlns='jabber:client' to='" + rosterjid + "' type='set' id='" + UUID.randomUUID().toString() + "'><query xmlns='jabber:iq:roster'><item jid='" + client.getBareJID() + "' subscription='to' /></query></iq>").getBytes());
                    rosterwriter.write(("<iq xmlns='jabber:client' to='" + rosterjid + "' type='set' id='" + UUID.randomUUID().toString() + "'><query xmlns='jabber:iq:roster'><item jid='" + client.getBareJID() + "' subscription='both' /></query></iq>").getBytes());
                    rosterwriter.write(("<presence xmlns='jabber:client' from='" + client.getJid() + "' to='" + to + "'><status>" + client.getPresencemanager().getStatus() + "</status><priority>" + client.getPresencemanager().getpriority() + "</priority><x xmlns='vcard-temp:x:update' /></presence>").getBytes());
                    rosterwriter.write(("<iq xmlns='jabber:client' to='" + rosterjid + "' type='set' id='" + UUID.randomUUID().toString() + "'><query xmlns='jabber:iq:roster'><item jid='" + client.getBareJID() + "' subscription='to' /></query></iq>").getBytes());
                    rosterwriter.write(("<iq xmlns='jabber:client' to='" + rosterjid + "' type='set' id='" + UUID.randomUUID().toString() + "'><query xmlns='jabber:iq:roster'><item jid='" + client.getBareJID() + "' subscription='both' /></query></iq>").getBytes());
                    rosterwriter.flush();

                    writer.write(("<iq xmlns='jabber:client' to='" + client.getJid() + "' type='set' id='" + UUID.randomUUID().toString() + "'><query xmlns='jabber:iq:roster'><item ask='subscribe' jid='" + to + "' subscription='from' /></query></iq>").getBytes());
                    writer.write(("<presence xmlns='jabber:client' from='" + to + "' to='" + client.getBareJID() + "' type='subscribed' />").getBytes());
                    writer.write(("<iq xmlns='jabber:client' to='" + client.getJid() + "' type='set' id='" + UUID.randomUUID().toString() + "'><query xmlns='jabber:iq:roster'><item jid='" + to + "' subscription='both' /></query></iq>").getBytes());
                    writer.write(("<presence xmlns='jabber:client' from='" + rosterjid + "' to='" + client.getBareJID() + "'><status>" + cli.getPresencemanager().getStatus() + "</status><priority>" + cli.getPresencemanager().getpriority() + "</priority><x xmlns='vcard-temp:x:update' /></presence>").getBytes());
                    writer.flush();

                    client.getRoster().getRosteritems().put(cli.getUsername(),"both");

                    DBManager.updateRoster(client.getUsername(), "both", to.substring(0, to.indexOf("@")));

                    //DBManager.updateChatHistory(client.getJid().toString(), rosterjid, msg, timestamp, false);



                }  catch (IOException ex) {
                    Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
                }


            }
        }
    }


    public void sendSubscriptionRejectedResponse(String to) {
        Map userjids = Users.getUserjidlist();
        Map users = Users.getUserlist();

        System.out.println(to + ":" + to.substring(0, to.indexOf('@')));
        if (!users.containsKey(to) && !userjids.containsKey(to.substring(0, to.indexOf('@')))) {
            System.out.println("User Offline : " + to);
            //DBManager.updateChatHistory(client.getJid().toString(), to, msg, timestamp, true);
            return;
        }

        String usrkey = to.substring(0, to.indexOf('@'));
        if (userjids.containsKey(usrkey)) {
            List list = (List) userjids.get(usrkey);
            Iterator itr = list.iterator();
            while (itr.hasNext()) {
                try {
                    String rosterjid = (String) itr.next();
                    XMPPClient cli = (XMPPClient) users.get(rosterjid);
                    System.out.println(rosterjid + " : " + cli.getUsername());
                    DataOutputStream rosterwriter = cli.getWriter();

                    rosterwriter.write(("<presence xmlns='jabber:client' from='" + client.getJid() + "' to='" + to + "' type='unavailable' />").getBytes());
                    rosterwriter.write(("<presence xmlns='jabber:client' from='" + client.getBareJID() + "' to='" + to + "' type='unsubscribed' />").getBytes());
                   rosterwriter.write(("<iq xmlns='jabber:client' to='" + rosterjid + "' type='set' id='" + UUID.randomUUID().toString() + "'><query xmlns='jabber:iq:roster'><item jid='" + client.getBareJID() + "' subscription='none' /></query></iq>").getBytes());
                    rosterwriter.flush();

                    //DBManager.updateRoster(client.getUsername(), "both", to.substring(0, to.indexOf("@")));

                    //DBManager.updateChatHistory(client.getJid().toString(), rosterjid, msg, timestamp, false);



                }  catch (IOException ex) {
                    Logger.getLogger(XMPPPacketWriter.class.getName()).log(Level.SEVERE, null, ex);
                }


            }
        }
    }

    public void run() {
    }
}
